
package com.hexinfo.dmpro.script.pack.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hexinfo.dmpro.common.base.PageResult;
import com.hexinfo.dmpro.common.model.ClusterSparingConf;
import com.hexinfo.dmpro.common.service.ClusterSparingConfService;
import com.hexinfo.dmpro.common.utils.CommonConstants;
import com.hexinfo.dmpro.script.config.model.ConfigPathGit;
import com.hexinfo.dmpro.script.config.service.impl.ConfigPathGitServiceImpl;
import com.hexinfo.dmpro.script.pack.dao.ScriptPackTaskMapper;
import com.hexinfo.dmpro.script.pack.entity.ScriptPackTaskEntity;
import com.hexinfo.dmpro.script.pack.service.IScanScriptFileService;
import com.hexinfo.dmpro.script.pack.service.IScriptPackScanListService;
import com.hexinfo.dmpro.script.pack.service.IScriptPackTaskService;
import com.hexinfo.dmpro.script.pack.service.IScriptScanService;
import com.hexinfo.dmpro.script.pack.utils.GitUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 脚本打包任务表
 *
 * @author WZH
 * @date 2023-09-13 16:13:23
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class ScriptPackTaskServiceImpl extends ServiceImpl<ScriptPackTaskMapper, ScriptPackTaskEntity> implements IScriptPackTaskService {

    private final ClusterSparingConfService clusterSparingConfService;

    private final IScriptScanService scriptScanService;

    private final IScriptPackScanListService scriptPackScanListService;

    private final IScanScriptFileService scanScriptFileService;

    private final ScriptPackTaskMapper scriptPackTaskMapper;

    private final ConfigPathGitServiceImpl configPathGitService;

    @Value("${script.pack.relativePath}")
    private String relativePath;

    @Value("${script.pack.zipPath}")
    private String zipPath;

    @Value("${git-info.username}")
    private String gitUsername;

    @Value("${git-info.password}")
    private String gitPassword;

    private final static String PACK_PATH_TMPLATE = "{}/pack/{}/{}/";

    /*
     * @Method: createPackTask <br>
     * @Param: [scriptPackTask] <br>
     * @Return: java.lang.String <br>
     * @Description：创建扫描任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/10/7 18:46 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public String createPackTask(ScriptPackTaskEntity scriptPackTask) {
        try {
            // 保存任务
            this.save(scriptPackTask);
            if (StrUtil.equals(scriptPackTask.getFileObtainingType(), "git")) {
                // 处理Git拉取的代码
                delGitCode(scriptPackTask);
            }
            // 归档总包文件
            archiveMasterPackage(scriptPackTask);
            this.updateById(scriptPackTask);
            scriptScanService.scriptFileScan(scriptPackTask);
            return scriptPackTask.getId();
        } catch (Exception e) {
            if (StrUtil.isNotEmpty(scriptPackTask.getId())) {
                removeById(scriptPackTask.getId());
            }
            throw new RuntimeException("创建扫描任务发生异常: " + e.getMessage(), e);
        }
    }

    /**
     * @Method delGitCode
     * @Param
     * @param scriptPackTask
     * @Return void
     * @Description 处理Git拉取的代码
     * @Author Wang zhihao
     * @Date 2024/1/18 15:50
     * @Version V1.0
     */
    private void delGitCode(ScriptPackTaskEntity scriptPackTask) {
        String uploadFilePath = StrUtil.format("{}/tmp/{}/{}/{}", relativePath, DateUtil.today(), System.currentTimeMillis(), scriptPackTask.getGitBranchName());
        //根据gitPath获取用户名密码
        ConfigPathGit configPathGit = new ConfigPathGit();
        configPathGit.setGitpath(scriptPackTask.getGitUrl());
        List<ConfigPathGit> configPathGitList = configPathGitService.queryListNoPage(configPathGit);
        String username = configPathGitList.get(0).getUsername();
        String password = configPathGitList.get(0).getPassword();
        // 拉取git代码到指定路径
        GitUtil.cloneGit(scriptPackTask.getGitUrl(), scriptPackTask.getGitBranchName(), uploadFilePath, username, password);
        // 压缩待扫描文件并获取其路径
        String zipPackagePath = createZipPackage(uploadFilePath);
        scriptPackTask.setTempPackagePath(zipPackagePath);
    }

    /**
     * @Method createZipPackage
     * @Param
     * @param localDir
     * @Return java.lang.String
     * @Description 创建压缩包
     * @Author Wang zhihao
     * @Date 2024/1/31 11:15
     * @Version V1.0
     */
    private static String createZipPackage(String localDir) {
        try {
            String zipFilePath = localDir + ".zip";
            ZipUtil.zip(localDir, zipFilePath, true);
            return zipFilePath;
        } catch (Exception e) {
            throw new RuntimeException("压缩待扫描的脚步文件包异常: " + e.getMessage(), e);
        }
    }

    /**
     * @Method archiveMasterPackage
     * @Param
     * @param scriptPackTask
     * @Return void
     * @Description 归档总包文件
     * @Author Wang zhihao
     * @Date 2023/12/12 14:58
     * @Version V1.0
     */
    private void archiveMasterPackage(ScriptPackTaskEntity scriptPackTask) {
        String masterPackageArchivePath = StrUtil.format(PACK_PATH_TMPLATE, relativePath, scriptPackTask.getId(), "master_package");
        copyFile(scriptPackTask.getTempPackagePath(), masterPackageArchivePath);
    }

    /**
     * @Method copyFile
     * @Param
     * @param sourcePath
     * @param targetPath
     * @Return void
     * @Description 复制文件
     * @Author Wang zhihao
     * @Date 2024/1/31 11:16
     * @Version V1.0
     */
    private void copyFile(String sourcePath, String targetPath) {
        File sourceFile = new File(sourcePath);
        if (FileUtil.getType(sourceFile).equalsIgnoreCase("zip")) {
            ZipUtil.unzip(sourceFile, new File(targetPath), CharsetUtil.CHARSET_GBK);
        } else {
            FileUtil.copyFilesFromDir(sourceFile, new File(targetPath + File.separator + sourceFile.getName()), true);
        }
    }

    /**
     * @param page
     * @param scriptPackTask
     * @Method queryList
     * @Param
     * @Return com.hexinfo.dmpro.common.base.PageResult
     * @Description 分页查询
     * @Author Wang zhihao
     * @Date 2023/9/14 17:47
     * @Version V1.0
     */
    @Override
    public PageResult queryList(Page page, ScriptPackTaskEntity scriptPackTask) {
        LambdaQueryWrapper<ScriptPackTaskEntity> wrapper = beforeQuery(scriptPackTask);
        Page returnPage = this.baseMapper.selectPage(page, wrapper);
        afterQuery(returnPage.getRecords());
        return new PageResult(returnPage.getRecords(), returnPage.getTotal());
    }

    /*
     * @Method: beforeQuery <br>
     * @Param: [scriptPackTask] <br>
     * @Return: com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.hexinfo.dmpro.script.pack.model.ScriptPackTask> <br>
     * @Description：分页查询前查询条件设置<br>
     * @Author： wz.li<br>
     * @Date： 2023/10/7 11:20 <br>
     * @Version： V2.0.2<br>
     */
    private LambdaQueryWrapper<ScriptPackTaskEntity> beforeQuery(ScriptPackTaskEntity scriptPackTask) {
        LambdaQueryWrapper<ScriptPackTaskEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ScriptPackTaskEntity::getDel, CommonConstants.STATUS_NORMAL);
        if (StrUtil.isNotBlank(scriptPackTask.getScriptPackName())) {
            wrapper.like(ScriptPackTaskEntity::getScriptPackName, scriptPackTask.getScriptPackName());
        }
        if (StrUtil.isNotBlank(scriptPackTask.getClusterId())) {
            wrapper.eq(ScriptPackTaskEntity::getClusterId, scriptPackTask.getClusterId());
        }
        if (StrUtil.isNotBlank(scriptPackTask.getPackState())) {
            wrapper.eq(ScriptPackTaskEntity::getPackState, scriptPackTask.getPackState());
        }
        wrapper.orderByDesc(ScriptPackTaskEntity::getCreateTime);
        return wrapper;
    }

    /*
     * @Method: afterQuery <br>
     * @Param: [scriptPackTaskList] <br>
     * @Return: void <br>
     * @Description：分页查询后置数据处理<br>
     * @Author： wz.li<br>
     * @Date： 2023/10/7 11:30 <br>
     * @Version： V2.0.2<br>
     */
    private void afterQuery(List<ScriptPackTaskEntity> scriptPackTaskList) {
        for (ScriptPackTaskEntity scriptPackTask : scriptPackTaskList) {
            ClusterSparingConf clusterSparingConf = clusterSparingConfService.getById(scriptPackTask.getClusterId());
            if (clusterSparingConf != null) {
                scriptPackTask.setClusterName(clusterSparingConf.getClusterName());
            }
/*            // 若该任务状态未完成，检查并刷新其状态
            if (!StrUtil.equalsIgnoreCase(scriptPackTask.getPackState(), "SCANFINISH")) {
                scanScriptFileService.refreshTaskState(scriptPackTask.getId());
            }*/
        }
    }

    /**
     * @param ids
     * @Method removeByIds
     * @Param
     * @Return void
     * @Description 批量删除
     * @Author Wang zhihao
     * @Date 2023/9/14 17:47
     * @Version V1.0
     */
    @Override
    public void removeByIds(List<String> ids) {
        ids.forEach(this::removeById);
    }

    /**
     * @Method removeById
     * @Param
     * @param id
     * @Return void
     * @Description 删除任务及列表/清单
     * @Author Wang zhihao
     * @Date 2023/10/18 19:06
     * @Version V1.0
     */
    @Override
    public void removeById(String id) {
        updateById(new ScriptPackTaskEntity().setId(id).setDel(CommonConstants.STATUS_DEL));
        scriptPackScanListService.removeByTaskId(id);
    }


    /**
     * @param multipartFile
     * @Method upload
     * @Param
     * @Return java.util.List<java.io.File>
     * @Description 上传
     * @Author Wang zhihao
     * @Date 2023/9/15 15:13
     * @Version V1.0
     */
    @Override
    public String upload(MultipartFile multipartFile) {
        try {
            if (multipartFile == null) {
                throw new RuntimeException("请选择上传的文件");
            }
            String uploadFilePath = StrUtil.format("{}/tmp/{}/{}", relativePath, DateUtil.today(), System.currentTimeMillis());
            File uploadFile = new File(uploadFilePath + File.separator + multipartFile.getOriginalFilename());
            FileUtil.touch(uploadFile);
            multipartFile.transferTo(uploadFile);
            return uploadFile.getPath();
        } catch (Exception e) {
            log.error("文件上传失败：{}", e.getMessage(), e);
            throw new RuntimeException(StrUtil.format("文件上传失败：{}", e.getMessage()));
        }
    }

    /**
     * @Method packById
     * @Param
     * @param scriptPackTask
     * @Return void
     * @Description 打包
     * @Author Wang zhihao
     * @Date 2023/10/15 19:20
     * @Version V1.0
     */
    @Override
    public ScriptPackTaskEntity packFile(ScriptPackTaskEntity scriptPackTask) {
        ZipUtil.zip(relativePath + "/pack/" + scriptPackTask.getId(), zipPath + scriptPackTask.getFilePackName());
        ScriptPackTaskEntity scriptPackTaskEntity = baseMapper.selectById(scriptPackTask.getId());
        scriptPackTask.setFilePackPath(zipPath + scriptPackTask.getFilePackName());
        scriptPackTask.setMasterPackagePath(scriptPackTaskEntity.getMasterPackagePath());
        return scriptPackTask;
    }

    /**
     * @Method modifyScanSuccessNum
     * @Param
     * @param taskId
     * @Return void
     * @Description 更新成功数量
     * @Author Wang zhihao
     * @Date 2024/1/31 10:57
     * @Version V1.0
     */
    @Override
    public void modifyScanSuccessNum(String taskId) {
        scriptPackTaskMapper.modifyScanSuccessNum(taskId);
        scriptPackTaskMapper.modifyScanStatus(taskId);
    }

    /**
     * @Method modifyScanWarnNum
     * @Param
     * @param taskId
     * @Return void
     * @Description 更新告警数量
     * @Author Wang zhihao
     * @Date 2024/1/31 11:43
     * @Version V1.0
     */
    @Override
    public void modifyScanWarnNum(String taskId) {
        scriptPackTaskMapper.modifyScanWarnNum(taskId);
        scriptPackTaskMapper.modifyScanStatus(taskId);
    }

    /**
     * @Method modifyScanErrorNum
     * @Param
     * @param taskId
     * @Return void
     * @Description 更新异常数量
     * @Author Wang zhihao
     * @Date 2024/1/31 11:43
     * @Version V1.0
     */
    @Override
    public void modifyScanErrorNum(String taskId) {
        scriptPackTaskMapper.modifyScanErrorNum(taskId);
        scriptPackTaskMapper.modifyScanStatus(taskId);
    }

    /**
     * @Method modifyScanFailNum
     * @Param
     * @param taskId
     * @Return void
     * @Description 更新失败数量
     * @Author Wang zhihao
     * @Date 2024/1/31 10:57
     * @Version V1.0
     */
    @Override
    public void modifyScanFailNum(String taskId) {
        scriptPackTaskMapper.modifyScanFailNum(taskId);
        scriptPackTaskMapper.modifyScanStatus(taskId);
    }

}
